﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace game
{
    public abstract class GameObject
    {
        public enum DrawPhase
        {
            Opaque,
            Shadow,
            Reflection,
            Transparent,
        }

        public bool IsMultiLayer { get; set; }

        public Vector3 Position { get { return position; } set { position = value; } }
        protected Vector3 position;
        public Vector3 Rotation { get { return rotation; } set { rotation = value; } }
        protected Vector3 rotation;
        public Vector3 Scale { get { return scale; } set { scale = value; } }
        protected Vector3 scale;

        public Matrix World { get; protected set; }

        public int LayerIndex { get; protected set; }

        // used only if IsMultiLayer = true
        public int HLayerIndex { get; protected set; }
        public int LLayerIndex { get; protected set; }
        //

        protected float moveSpeed;
        protected Vector3 moveDir;
        protected Vector3 velocity;
             
        protected Scene scene = null;

        protected BoundingSphere bSphere;
        protected BoundingSphere bSphereTransformed;
        protected bool bSphereTransformedUpToDate = false;

        public virtual BoundingSphere GetBSphereTransformed()
        {
            if (!bSphereTransformedUpToDate)
            {
                bSphereTransformed = bSphere.Transform(World);
                bSphereTransformedUpToDate = true;
            }
            return bSphereTransformed;
        }

        public bool Culled { get; set; }


        public GameObject(Scene scene, int layerIndex)
        {
            this.scene = scene;
            this.LayerIndex = layerIndex;
            World = Matrix.Identity;
            bSphere = new BoundingSphere();
            Scale = new Vector3(1, 1, 1);
            Rotation = new Vector3(0, 0, 0);
            Position = new Vector3(0, 0, 0);
            IsAlive = true;
            IsMultiLayer = false;
        }

        public virtual void Update(GameTime gameTime)
        {
            World = Matrix.CreateScale(scale) * Matrix.CreateTranslation(position);
            bSphereTransformedUpToDate = false;
        }

        public void SetMultiLayer(int lowestLayerIndex, int highestLayerIndex)
        {
            if (lowestLayerIndex > highestLayerIndex)
                throw new Exception("GameObject: attempt to set wrong layer indices");
            LLayerIndex = lowestLayerIndex;
            HLayerIndex = highestLayerIndex;
            IsMultiLayer = true;
        }

        #region Drawing
        public void Draw(GameTime gameTime, DrawPhase drawPhase)
        {
            switch (drawPhase)
            {
                case DrawPhase.Opaque:
                    DrawOpaque(gameTime);
                    break;

                case DrawPhase.Transparent:
                    DrawTransparent(gameTime);
                    break;
            }
        }

        public virtual void DrawOpaque(GameTime gameTime) { }
        public virtual void DrawShadow(GameTime gameTime) { }
        public virtual void DrawReflection(GameTime gameTime) { }
        public virtual void DrawTransparent(GameTime gameTime) { }

        public virtual void DrawWithCustomShader(GameTime gameTime, SingleMatrixShader shader) { }

        #endregion

        #region Collisions

        public virtual bool Collide(GameObject obj)
        {
            return true;
        }

        public virtual void Collision(GameObject obj)
        {
        }

        public virtual float GetDamage()
        {
            return 0;
        }

        public bool IsAlive { get; protected set; }
        #endregion

        #region PostProcess

        public List<PostProcessEffectType> PPEffectTypes { get; protected set; }

        public virtual void DrawPostProcess(GameTime gameTime, PostProcessEffect ppEffect)
        {
        }

        #endregion
    }
}
